package com.yy.young.log.core;

import com.yy.young.interfaces.log.model.LogDTO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 日志服务控制
 * Created by rookie on 2017/11/10.
 */
@Component
@Scope("singleton")
public class LogControl {

    /**
     * 日志队列,用于存放日志信息
     * 基于链表的阻塞队列,使用2把锁来分别管理读和写,并发性能更好.
     */
    private static LinkedBlockingQueue<LogDTO> logQueue = new LinkedBlockingQueue<LogDTO>();

    /**
     * 线程池,用于处理LogCatchTask
     */
    private static ExecutorService threadPool = Executors.newFixedThreadPool(10);

    /**
     * 消费线程池,用于处理日志消费任务
     */
    private static ExecutorService threadPool2 = Executors.newFixedThreadPool(10);

    /**
     * 已捕获日志总数,原子操作int,避免高并发下的线程安全问题
     */
    private static AtomicInteger catchLogNum = new AtomicInteger();

    private static final Logger logger = LoggerFactory.getLogger(LogControl.class);

    /**
     * 抓捕日志(异步)
     * @param joinPoint 切入点对象
     * @param logDTO 日志对象
     */
    public static void catchLog(ProceedingJoinPoint joinPoint, LogDTO logDTO){
        threadPool.execute(new LogCatchTask(joinPoint, logDTO));
    }

    /**
     * 添加日志到队列中,供日志捕获器LogCatchTask向日志控制中心添加日志对象
     * @param logDTO
     */
    public static void put(LogDTO logDTO){
        try {
            logQueue.put(logDTO);
            catchLogNum.incrementAndGet();//日志数自增
        } catch (InterruptedException e) {
            logger.error("[Young日志服务] 日志存入队列失败! {}", logDTO);
            e.printStackTrace();
        }
    }

    //spring创建该bean后执行该方法,开始日志消费
    @PostConstruct
    public void consumeStart(){
        logger.info("[Young日志服务] 日志消费线程启动!");
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.interrupted()){
                    try {
                        LogDTO logDTO = logQueue.take();
                        threadPool2.execute(new LogConsumeTask(logDTO));
                    } catch (InterruptedException e) {
                        logger.error("[Young日志服务] 从队列获取日志失败!");
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @PreDestroy
    public void destroy(){
        logger.info("[Young日志服务] 销毁处理开始...");
        if(logQueue.size() > 0){
            logger.error("[Young日志服务] 当前日志队列长度为{},销毁可能会导致部分日志丢失!", logQueue.size());
        }else{
            logger.info("[Young日志服务] 日志队列为空,可以进行销毁!");
        }
        logger.info("[Young日志服务] 销毁处理结束!");
    }
}
